<?php
/**     
*
* Copyright (c) 2009, Persistent Systems Limited
*
* Redistribution and use, with or without modification, are permitted 
*  provided that the following  conditions are met:
*   - Redistributions of source code must retain the above copyright notice, 
*     this list of conditions and the following disclaimer.
*   - Neither the name of Persistent Systems Limited nor the names of its contributors 
*     may be used to endorse or promote products derived from this software 
*     without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

/**
 * Class CurlRequest for send HTTP request using curl
 * @access public
 */
class CurlRequest
{
    /**
     * The URL to which cURL request needs to be sent
     *
     * @var string $url
     * @access public
     */
    public $url;

    /**
     * Whether or not to include header in the response
     * of the cURL request
     *
     * @var boolean $Header
     */
    public $Header = false;

    /**
     * Whether or not to follow HTTP Location headers.
     *
     * @var boolean $followLocation
     * @access public
     */
    public $followLocation = true;


    /**
     * Whether or not to return the results of the
     * current transfer
     *
     * @var boolean $returnTransfer
     * @access public
     */
    public $returnTransfer = true;


    /**
     * Whether or not to varify SSL
     * 
     *
     * @var boolean $varifyTransfer
     * @access public
     */
    public $varifyTransfer = false;

    /**
     * The type of transfer to perform (ie. 'POST', 'GET', 'PUT' or 'DELETE' )
     *
     * @var string $httpVerb
     * @access public
     */
    public $httpVerb;

    /**
     * Custom HTTP headers to send to the url
     *
     * @var array $httpHeaders
     * @access public
     */
    public $httpHeaders = null;

    /**
     * The fields to send in a 'POST' request.it needs to be passed as a 
     * urlencoded string like 'para1=val1&para2=val2&...' 
     *
     * @var String $postFields
     * @access public
     */
    public $postFields;

     /**
     * The fields to send in a 'PUT' request.  
     *
     * @var String $putFields
     * @access public
     */
    public $putFields;

    /**
     * The proxy server to go through
     *
     * @var object $httpWebProxy
     * @access public
     */
    public $_httpWebProxy;

    /**
     * The curl handle for the curl transfer in process
     *
     * @var resource $_handle
     * @access private
     * @see curlRequest::process()
     */
     private $_handle = null;

       
    /**
     * The CurlRequest constructor, called when a new CurlRequest object
     * is initialized  
     *
     * @param string $url       The URL to send cURL request to (can be set using the $url 
     *                          property too)
     *
     * @access public
     * @return void
     */
    function __construct($url = '')
    {
        if (is_string($url) && strlen($url)) {
            $this->url = $url;
        }
    }
    
    /**
     * Sets proxy details for the cURL transfer. This uses object of class httpWebProxy 
     * with proxy values like host,port and password
     *
     * @param object $httpWebProxy  object of httpWebProxy class
     * 
     * @access public
     * @see httpWebProxy
     */
    public function setHttpWebProxy($httpWebProxy)
    {
        $this->_httpWebProxy = $httpWebProxy;

    }

    /**
     * processs a prepared CURL transfer
     *
     * Run this function to process the cURL request. On success response is returned 
     * and an error is returned if something fails
     *
     *
     * @access public
     * @return error on failure, response on success
     */
    function process()
    {
        // Initiate cURL handle if it hasn't already been initiated
        if (!is_resource($this->_handle)) 
        {
            try
            {
                $result = $this->init();
            }
            catch(Exception $cError )
            {
                return $cError.getMessage();
            }
        }
        
        

       

               
        // set url to work on and header flag
        curl_setopt($this->_handle, CURLOPT_URL, $this->url);
        curl_setopt($this->_handle, CURLOPT_HEADER, $this->Header);

        // Whether or not to return the transfer contents
        if ($this->returnTransfer === true) 
        {
            curl_setopt($this->_handle, CURLOPT_RETURNTRANSFER, true);
        }
        
        // Whether or not to return the transfer contents
        if ($this->varifyTransfer === false) 
        {
            curl_setopt($this->_handle, CURLOPT_SSL_VERIFYPEER, false);
        }
        

        // check and set if proxy is required
        if (isset($this->_httpWebProxy)) 
        {
            //set avaliable values from the httpWebProxy object
            if (!empty($this->_httpWebProxy))
            {
                if (!empty($this->_httpWebProxy->_host))
                {
                    //set the proxy host
                    curl_setopt($this->_handle, CURLOPT_PROXY, $this->_httpWebProxy->_host);
                }

                if (!empty($this->_httpWebProxy->_port))
                {
                    //set the proxy port
                    curl_setopt($this->_handle, CURLOPT_PROXYPORT, $this->_httpWebProxy->_port);
                }

                if (!empty($this->_httpWebProxy->_username)|| !empty($this->_httpWebProxy->_password))
                {
                    //set the proxy user and password
                    curl_setopt($this->_handle, 
                               CURLOPT_PROXYUSERPWD, 
                               $this->_httpWebProxy->_username . ':' . $this->_httpWebProxy->_password);
                }
             }
        }

        // set reuest type
        if (isset($this->httpVerb)) 
        {
            switch (strtolower($this->httpVerb)) 
            {
                case 'post':
                    curl_setopt($this->_handle, CURLOPT_POST, true);
                    break;
                case 'put':
                    curl_setopt($this->_handle, CURLOPT_POST, true);
                    curl_setopt($this->_handle, CURLOPT_CUSTOMREQUEST, 'PUT');
                    break;
                case 'delete':
                    curl_setopt($this->_handle, CURLOPT_CUSTOMREQUEST, 'DELETE');
                    break;
            }

        }
        
        // set the postfields string
        if (isset($this->postFields)) 
        {
            $sets = null;
            if (!isset($this->httpVerb)) 
            {
                //post fileds can be sent over POST request so set POST as a request type
                $this->httpVerb = 'post';
                curl_setopt($this->_handle, CURLOPT_POST, true);
            }

            //set the postfield string
            curl_setopt($this->_handle, CURLOPT_POSTFIELDS, $this->postFields);
        }

        // set the postfields string
        if (isset($this->putFields)) 
        {
            $sets = null;
            if (!isset($this->httpVerb)) 
            {
                //post fileds can be sent over POST request so set POST as a request type
                $this->httpVerb = 'put';                
                curl_setopt($this->_handle, CURLOPT_POST, true);
                curl_setopt($this->_handle, CURLOPT_CUSTOMREQUEST, 'PUT');
            }           
            curl_setopt($this->_handle, CURLOPT_POSTFIELDS, $this->putFields);            
        }

                
        // Whether or not to follow the header location
        curl_setopt($this->_handle,
                           CURLOPT_FOLLOWLOCATION, 
                           $this->followLocation);

        // Add other HTTP headers
        if ($this->httpHeaders !== null) 
        {
            if (is_array($this->httpHeaders)) 
            {
                foreach ($this->httpHeaders as $key => $value)
                {
                    $curlHeaders[] = $key.': '.$value;
                }
                curl_setopt($this->_handle, 
                                   CURLOPT_HTTPHEADER, 
                                   $curlHeaders);
            } 
            else 
            {
                throw new Exception('Curl Error for URL: ' . $this->url . ', CurlRequest::$httpHeaders must be an array');
            }
        }
        $response = null;
        $response = curl_exec($this->_handle);
                
        if (curl_errno($this->_handle)) 
        {
            $errorMessage = 'Curl Error for URL: ' . $this->url . ', Message: ' . 
                            curl_error($this->_handle) . '  No :' . curl_errno($this->_handle);
            throw new Exception($errorMessage);
        }

        return $response;
    }
 
    /**
     * Sets an option for your cURL session. Please note that the cURL handler
     * is NOT initiated before process(). This is for error checking purposes.
     * You should use setOption() in the following manner:
     *
     *
     * @param int   $option cURL constant (ie. CURLOPT_URL)
     * @param mixed $value  The option's value
     * 
     * @access public
     * @return boolean
     */
    function setOption($option, $value)
    {
        if (is_resource($this->_handle)) 
        {
            return curl_setopt($this->_handle, $option, $value);
        }

        return false;
    }

    /**
     * Returns the info from the cURL session. error if you try and run
     * this before you process the session.
     *
     * @access public
     * @return mixed error if there is no resource, info on success
     */
    function getInfo()
    {
        if (is_resource($this->_handle)) 
        {
            return curl_getinfo($this->_handle);
        }

        return 'cURL handler does not exist';
    }

    /**
     * Returns the curl error number from the cURL session. error if you try and run
     * this before you process the session.
     *
     * @access public
     * @return String error if there is no resource, error number on success
     */
    function getErrorNo()
    {
        if (curl_errno($this->_handle)) 
        {
            return curl_errno($this->_handle);
        }
    }

    /**
     * Initiates a cURL resource. If curl_init() doesn't exist or initiation fails
     * an error is returned.
     * @return boolean TRUE on success, error on failure
     */
    function init()
    {
        if (!function_exists('curl_init')) 
        {
            return 'Function curl_init() not found';
        }

        $this->_handle = curl_init();
        if (!is_resource($this->_handle)) 
        {
            return 'Could not initialize cURL handler';
        }

        return true;
    }

    
    /**
     * Closes the cURL request handle 
     *
     * @access public
     */
    function close()
    {
        if (is_resource($this->_handle)) 
        {
            curl_close($this->_handle);
        }
    }


    /**
     * Destructor.
     *
     * Runs CurlRequest::close() to close our cURL connection.
     *
     * @see CurlRequest::close()
     */
    function __destruct()
    {
        $this->close();
    }
}
?>
